<?php

/**
* a webappkit tool to execute unit tests using a test database.
* sometimes you can't or don't want to use mock database connectors
* but don't want either to mess up your real data.
*
* this tool creates a fake database before issuing tests, and drop it after.
* insert the fake database definition into tool configuration file as this :
* [db]
* name = "fake database name"
* ; following data is optional, current connection will be used if existing
* host = ""
* user = ""
* pwd = ""
* [tables]
* ; name = "SQL creation command on a single line"
* mytable = "CREATE TABLE mytable(id primary key integer not null, value varchar(128))"
* [data]
* ; anykey = "row insertion command on a single line"
*/
class SimpleTestMysqlTool extends SimpleTestTool {

    function toolFactory($kit,$cfg) {
        return new SimpleTestMysqlTool($kit,$cfg);
    }

    var $cfg=array(
        'db'=>array(
            'name'=>'unit_tests'
            ,'encoding'=>'utf8'
            ,'create'=>true
            ,'drop' => false
            ,'host'=>'localhost'
            ,'user'=>''
            ,'pwd'=>'')
        ,'structure'=>array()
        // table.field = "definition"
        // like users.login = "varchar(64) unique not null"
        ,'data'=>array()
    );

    var $encoding;

    function _init() {
        $this->db_name=isset($this->cfg['db']['name'])?$this->cfg['db']['name']:'test';
    }

    /**
     * connects to database server
     * creates tests db if necessary
     * creates tables and data
     */
    function setUp() {
        // connecting
        if (!$this->_connect()) {
            return false;
        }
        $this->_populateDb();
    }

    /**
     * eventually drop tests database
     */
    function tearDown() {
        // dropping test database
        if ($this->cfg['db']['drop']) {
            $sql = 'DROP DATABASE '.$this->db_name;
            if (!mysql_query($sql)) {
                trigger_error("could not drop database {$this->db_name} using query $sql",E_USER_WARNING);
            }
        }
    }

    /**
     * connects to database
     */
    function _connect() {
        $host=$this->cfg['db']['host'];
        $user=$this->cfg['db']['user'];
        $pwd=$this->cfg['db']['pwd'];
        if (!mysql_connect($host,$user,$pwd)) {
            trigger_error("could not connect to host {$host}",E_USER_WARNING);
            return false;
        }
        // set connexion encoding
        if ($this->cfg['db']['encoding'])
            $this->_setEncoding($this->cfg['db']['encoding']);
        // creating test database
        if ($this->cfg['db']['create']) {
            $sql='CREATE DATABASE IF NOT EXISTS '.$this->db_name;
            if ($this->encoding)
                $sql.=' CHARACTER SET '.$this->encoding;
            if (!mysql_query($sql)) {
                trigger_error("could not create database {$this->db_name} using query $sql",E_USER_WARNING);
            }
        }
        // switching to new database
        if (!mysql_select_db($this->db_name)) {
            trigger_error("could not switch to test database {$this->db_name}",E_USER_ERROR);
            // DO NOT ISSUE TEST TO ANOTHER DB !!!
            exit;
        }
        return true;
    }

    /**
     * eventually create tables and data
     * from the sql queries located in the config
     * @access protected
     * @return bool
     */
    function _populateDb() {
        // building tables
        if (!is_array($this->cfg['tables'])) {
            return false;
        }
        foreach ($this->cfg['tables'] as $table => $create_sql) {
            // dropping table if exists
            mysql_query('DROP TABLE '.$table);
            // creating table
            if (!mysql_query($create_sql)) {
                trigger_error("could not create table {$table} , error was ".mysql_error(),E_USER_WARNING);
                echo '<pre>'.$create_sql.'</pre>';
            }
        }
        // dumping test data
        if (!is_array($this->cfg['data'])) {
            return false;
        }
        foreach ($this->cfg['data'] as $line => $sql) {
            if (!mysql_query($sql)) {
                trigger_error("could not insert row {$line} using query $sql",E_USER_WARNING);
                echo mysql_error();
            }
        }
        return true;
    }

    /**
     * set encoding for connexion
     * @param string encoding
     */
    function _setEncoding($encoding) {
        // MySQL 4.1
        if (!$this->_query("SET NAMES '$encoding'")
        // MySQL 4.0
        and !$this->_query("SET CHARACTER SET '$encoding'")) {
            trigger_error("failed to set encoding $encoding : ".mysql_error());
            return false;
        }
        $this->encoding=$encoding;
        return true;
    }

    /**
     * execute a query
     */
    function _query($sql) {
        return mysql_query($sql);
    }
}
